package cn.ee.dfs.common.utils;
import cn.ee.dfs.common.entity.WsdlEntity;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.springframework.util.StringUtils;
import org.w3c.dom.Document;

import javax.wsdl.*;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.wsdl.xml.WSDLWriter;
import javax.xml.namespace.QName;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;

/**
 * 基本功能：wsdl文件解析工具类
 * 创建人：王杰
 * 创建时间： 2017-09-26 下午10:32
 **/
public class WsdlUtils {
    public static int flag = 2;//1为演示使用，2为正式使用，生产环境flag必须为2
    public static void main(String[] args) {
        String webServiceUrl = "http://www.sjz40z.com:8008/EastEliteSMSWS.asmx";
        List<WsdlEntity> string = getMethods(webServiceUrl);
        System.out.println(string);
    }
    public static List<WsdlEntity> getMethods(String webServiceUrl) {

        List<String> methods = new ArrayList<String>();
        List<WsdlEntity> wsdlEntitys = new ArrayList<WsdlEntity>();
        try {
            WSDLFactory factory = WSDLFactory.newInstance();
            WSDLReader reader = factory.newWSDLReader();
            reader.setFeature("javax.wsdl.verbose", true);
            reader.setFeature("javax.wsdl.importDocuments", true);
            if (!webServiceUrl.endsWith("?wsdl")) {
                webServiceUrl = webServiceUrl + "?wsdl";
            }
            Definition def = reader.readWSDL(webServiceUrl);

            String namespaceURI = def.getTargetNamespace();
//            System.out.println("---- nameSpace  ->"+namespaceURI);
            String localPart = webServiceUrl.split("/")[webServiceUrl.split("/").length - 1];
            if (localPart.contains(".")) {
                localPart = localPart.split("\\.")[0];
            }
            Service service = def.getService(new QName(namespaceURI, localPart));
            String portStr = "";
            Map<?, ?> ports = service.getPorts();
            Iterator<?> itor = ports.entrySet().iterator();
            while (itor.hasNext()) {
                Map.Entry<?, ?> map = (Map.Entry<?, ?>) itor.next();
                Object key = map.getKey();
                portStr = (key == null ? "" : key.toString());
                break;
            }
            Port port = service.getPort(portStr);
            Binding binding = port.getBinding();
            PortType portType = binding.getPortType();
            List<?> operations = portType.getOperations();
            Iterator<?> operIter = operations.iterator();
            while (operIter.hasNext()) {
                Operation operation = (Operation) operIter.next();
                if (!operation.isUndefined()) {
                    methods.add(operation.getName());
                }
            }

            WSDLWriter writer = factory.newWSDLWriter();
            Document doc = writer.getDocument(def);
            TransformerFactory transformerFactory = TransformerFactory
                    .newInstance();
            Transformer transformer = null;
            try {
                transformer = transformerFactory.newTransformer();
            } catch (TransformerConfigurationException e) {
                e.printStackTrace();
            }
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
            DOMSource source = new DOMSource(doc);

            StringWriter strWtr = new StringWriter();
            StreamResult strResult = new StreamResult(strWtr);

            try {
                transformer.transform(source, strResult);
            } catch (TransformerException e) {
                e.printStackTrace();
            }
            String result = strResult.getWriter().toString();

            try {
                strWtr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (methods != null) {
                for (String method : methods) {
                    try {
                        if (flag==1){
                            switch (method){
                                case "GetTeacherNameListByClassCode":
                                case "GetStudentDetailInfoItem":
                                case "GetClassNameList":
                                case "getSupportCity":
                                case "getSupportProvince":
                                    WsdlEntity wsdlEntity = getMethodName(result, method);
                                    String responseStr = getResponse(result, method + "Response");
                                    wsdlEntity.setMethodResponse(responseStr);
                                    String docStr = getDoc(result, method);
                                    wsdlEntity.setMethodDoc(docStr);
                                    wsdlEntity.setTargetNamespace(namespaceURI);
                                    wsdlEntitys.add(wsdlEntity);
                                    break;
                                default:
                                    break;
                            }
                        }else {
                            WsdlEntity wsdlEntity = getMethodName(result, method);
                            String responseStr = getResponse(result, method + "Response");
                            wsdlEntity.setMethodResponse(responseStr);
                            String docStr = getDoc(result, method);
                            wsdlEntity.setMethodDoc(docStr);
                            wsdlEntity.setTargetNamespace(namespaceURI);
                            wsdlEntitys.add(wsdlEntity);
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (WSDLException e) {
            e.printStackTrace();
        }
        return wsdlEntitys;
    }
    /**
     * 方法名称和接收参数
     * @param xmlStr
     * @param requestStr
     * @return
     * @throws Exception
     */
    public static WsdlEntity getMethodName(final String xmlStr, final String requestStr)
            throws Exception {
        WsdlEntity wsdlEntity = new WsdlEntity();
        org.dom4j.Document document = DocumentHelper.parseText(xmlStr);
        // 获得节点的命名空间
        String uri = "http://www.w3.org/2001/XMLSchema";
        String uri2 = "http://schemas.xmlsoap.org/wsdl/";
        // 将uri存入map中
        HashMap map = new HashMap();
        map.put("xs", uri);
        map.put("wsdl", uri2);
        XPath xpath2 = DocumentHelper
                .createXPath("//wsdl:definitions//wsdl:types//xs:schema//xs:element[@name='" +
                        requestStr + "']//xs:complexType//xs:sequence//xs:element");
        xpath2.setNamespaceURIs(map);
        List list2 = xpath2.selectNodes(document);
        wsdlEntity.setMethodName(requestStr);
        String params = "";
        List<WsdlEntity.MethodParams> methodParamsList = new ArrayList<>();
        for (int i = 0; i < list2.size(); i++) {
            WsdlEntity.MethodParams methodParams = new WsdlEntity.MethodParams();
            Element e = (Element) list2.get(i);// 转型为Element
            String name = e.attributeValue("name");
            String type = e.attributeValue("type");
            if (!StringUtils.isEmpty(name)) {
                if (!StringUtils.isEmpty(type) && type.length() > 2) {
                    type = type.substring(2);
                    methodParams.setName(name);
                    methodParams.setType(type);
                }
            }
            methodParamsList.add(methodParams);
        }
        wsdlEntity.setMethodParams(methodParamsList);
        return wsdlEntity;
    }
    /**
     * 返回类型
     *
     * @param xmlStr
     * @param requestStr
     * @return
     * @throws Exception
     */
    public static String getResponse(final String xmlStr, final String requestStr)
            throws Exception {
        org.dom4j.Document document = DocumentHelper.parseText(xmlStr);
        // 获得节点的命名空间
        String uri = "http://www.w3.org/2001/XMLSchema";
        String uri2 = "http://schemas.xmlsoap.org/wsdl/";
        // 将uri存入map中
        HashMap map = new HashMap();
        map.put("xs", uri);
        map.put("wsdl", uri2);
        XPath xpath2 = DocumentHelper
                .createXPath("//wsdl:definitions//wsdl:types//xs:schema//xs:element[@name='" +
                        requestStr + "']//xs:complexType//xs:sequence//xs:element");

        xpath2.setNamespaceURIs(map);
        List list = xpath2.selectNodes(document);

        List list2 = xpath2.selectNodes(document);
        String result = "";
        for (int i = 0; i < list.size(); i++) {
            Element e = (Element) list2.get(i);// 转型为Element
            if (!StringUtils.isEmpty(e.attributeValue("type"))) {
                result += e.attributeValue("type");
            }
        }
        return result;
    }
    /**
     * 方法描述
     *
     * @param xmlStr
     * @param requestStr
     * @return
     * @throws Exception
     */
    public static String getDoc(final String xmlStr, final String requestStr)
            throws Exception {
        org.dom4j.Document document = DocumentHelper.parseText(xmlStr);
        // 获得节点的命名空间
        String uri = "http://www.w3.org/2001/XMLSchema";
        String uri2 = "http://schemas.xmlsoap.org/wsdl/";
        // 将uri存入map中
        HashMap map = new HashMap();
        map.put("xs", uri);
        map.put("wsdl", uri2);
        XPath xpath2 = DocumentHelper
                .createXPath("//wsdl:definitions//wsdl:portType//wsdl:operation[@name='" +
                        requestStr + "']//wsdl:documentation");
        xpath2.setNamespaceURIs(map);
        List list2 = xpath2.selectNodes(document);
        String result = "";
        if (list2 != null && list2.size() > 0) {
            Element e = (Element) list2.get(0);// 转型为Element
            result += e.getText();
        }
        return result;
    }
}